using System;
using System.Collections.Generic;

namespace Firestarter.DB.Schema.Logic
{
    public abstract class CreateTableSqlBuilder {

        public List<string> ForeignKeys { get; protected set; }
        public List<string> Columns { get; protected set; }
        public List<string> PrimaryKeyColumns { get; protected set; }
        public List<string> UniqueKeys { get; protected set; }

        protected CreateTableSqlBuilder(string tableName)
        {  
            TableName = tableName;
            ForeignKeys = new List<string>(4);
            Columns = new List<string>(4);
            PrimaryKeyColumns = new List<string>(2);
            UniqueKeys = new List<string>(2);
        }

        public string TableName { get; set; }

        public virtual void AddPrimaryKeyColumn(string columnName)
        {
            PrimaryKeyColumns.Add(Enclose(columnName));
            //return this;
        }

        public virtual void AddColumn(string columnName, string dataType, long? length, long? precision, bool nullable, bool autoIncrementing)
        {
            string nullableString = GetColumnNullableSQL(nullable);
            string autoIncrementString = GetColumnAutoIncrementSQL(autoIncrementing);
            if (!string.IsNullOrEmpty(autoIncrementString)) autoIncrementString = " " + autoIncrementString;
            string lengthSpecString = GetColumnDataLengthSQL(length, precision);
            Columns.Add(string.Format("{0} {1}{2} {3}{4}", Enclose(columnName), dataType, lengthSpecString, nullableString, autoIncrementString));
            //return this;
        }

        protected abstract string Enclose(string name);

        protected string EncloseList(string nameList)
        {
            string[] names = nameList.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            List<string> enclosedNames = new List<string>();
            foreach (string name in names)
            {
                enclosedNames.Add(Enclose(name.Trim()));
            }
            return String.Join(", ", enclosedNames.ToArray());
        }

        protected virtual string GetColumnDataLengthSQL(long? length, long? precision)
        {
            return length.HasValue ? string.Format("({0})", length) : "";
        }

        protected virtual string GetColumnAutoIncrementSQL(bool autoIncrementing)
        {
            return autoIncrementing ? "AUTO_INCREMENT" : "";
        }

        protected virtual string GetColumnNullableSQL(bool nullable)
        {
            return nullable ? "NULL" : "NOT NULL";
        }
        public abstract void AddForeignKey
            (string foreignKeyName, string parentColumnNameList, string referencedTableName,
             string referencedColumnNameList);

        public virtual void AddUniqueKey(string keyName, string columnNameList)
        {
            string createUniqueKey = string.Format("CONSTRAINT {0} UNIQUE ({1})", Enclose(keyName), EncloseList(columnNameList));
            UniqueKeys.Add(createUniqueKey);
        }
        public virtual string GetSql()
        {
            //TODO  16 Jan 2009: Should raise error if columnsSQL is null
            //TODO  16 Jan 2009: Should not build in PrimaryKey in if there is no primary key added.
            const string columnDelimiter = ", ";
            string columnsSql = String.Join(columnDelimiter, Columns.ToArray());
            string primaryKeyColumnList = String.Join(columnDelimiter, PrimaryKeyColumns.ToArray());
            if (!string.IsNullOrEmpty(primaryKeyColumnList))
            {
                string primaryKeySql = string.Format("PRIMARY KEY({0})", primaryKeyColumnList);
                columnsSql += columnDelimiter + primaryKeySql;
            }
            string foreignKeySQL = String.Join(columnDelimiter, this.ForeignKeys.ToArray());
            if (!string.IsNullOrEmpty(foreignKeySQL)) foreignKeySQL = columnDelimiter + foreignKeySQL;

            string uniqueKeySQL = string.Join(columnDelimiter, this.UniqueKeys.ToArray());
            if (!string.IsNullOrEmpty(uniqueKeySQL)) uniqueKeySQL = columnDelimiter + uniqueKeySQL;

            return String.Format("CREATE TABLE {0} ({1}{2}{3})", Enclose(TableName), columnsSql, foreignKeySQL, uniqueKeySQL);
        }
    }
}